package net.zdsoft.wpchat.android.util;

import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.ServletContext;

import org.springframework.context.ApplicationContext;
import org.springframework.util.StopWatch;
import org.springframework.web.context.support.WebApplicationContextUtils;

import net.zdsoft.keel.util.Validators;
import net.zdsoft.wpchat.support.service.SysOptionService;

/**
 * 判断手机号码类型的工具类. 和keel里的<tt>Validators</tt>工具类的手机号码类型判断方法相比,<br>
 * 增加了对于模拟手机号码的判断. 模拟手机号码格式:
 * <ul>
 * <li>0001xxxxxxxx 移动</li>
 * <li>0002xxxxxxxx 联通</li>
 * <li>0003xxxxxxxx 电信</li>
 * </ul>
 * 其中xxxxxxxx为8位数字.
 * 
 * @author xuan
 * @version $Revision: 1.0 $, $Date: 2014-9-22 下午10:39:06 $
 */
public class MobileUtils {

    @Resource
    private SysOptionService sysOptionService;

    private static MobileUtils mob;

    /**
     * 初始化方法, 设置获取判断手机号码类型的正则表达式的服务.
     * 
     */
    public void init() {
        mob = this;
        mob.sysOptionService = this.sysOptionService;
    }

    /**
     * 销毁方法。
     */
    public void destroy() {
    }

    /**
     * 是否为手机号码(<b>不包括虚拟号码</b>), 包括移动, 联通, 电信等手机号码.
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isRealMobile(String str) {
        return isRealChinaMobile(str) || isRealChinaUnicom(str) || isRealChinaTelecom(str);
    }

    /**
     * 是否为中国移动手机号码. 包括系统中模拟的移动号码: 0001xxxxxxxx(8位数字).
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isChinaMobileContainVirtual(String str) {
        if (Validators.isEmpty(str)) {
            return false;
        }

        return Pattern.matches(getMobileRegex(), str);
    }

    /**
     * 是否为中国移动手机号码(<b>不包括虚拟号码</b>).
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isRealChinaMobile(String str) {
        if (Validators.isEmpty(str)) {
            return false;
        }

        return Pattern.matches(getMobileRegex(), str) && !str.startsWith("0001");
    }

    /**
     * 是否为中国联通手机号码. 包括系统中模拟的联通号码: 0002xxxxxxxx(8位数字).
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isChinaUnicomContainVirtual(String str) {
        if (Validators.isEmpty(str)) {
            return false;
        }

        return Pattern.matches(getUnicomRegex(), str);
    }

    /**
     * 是否为中国联通手机号码(<b>不包括虚拟号码</b>).
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isRealChinaUnicom(String str) {
        if (Validators.isEmpty(str)) {
            return false;
        }

        return Pattern.matches(getUnicomRegex(), str) && !str.startsWith("0002");
    }

    /**
     * 是否为电信手机号码. 包括系统中模拟的电信号码: 0003xxxxxxxx(8位数字).
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isChinaTelecomContainVirtual(String str) {
        if (Validators.isEmpty(str)) {
            return false;
        }

        return Pattern.matches(getTelecomRegex(), str);
    }

    /**
     * 是否为电信手机号码(<b>不包括虚拟号码</b>).
     * 
     * @param str
     *            字符串
     * @return 若是合法的手机号码返回 <code>true</code>, 否则返回 <code>false</code>.
     */
    public static boolean isRealChinaTelecom(String str) {
        if (Validators.isEmpty(str)) {
            return false;
        }

        return Pattern.matches(getTelecomRegex(), str) && !str.startsWith("0003");
    }

    /**
     * 隐藏手机中间5位,(fixed by xuan)
     * 
     * @param phone
     * @return
     */
    public static String hideSomeNum(String phone) {
        return hideSomeNum(phone, 5);
    }

    /**
     * 根据参数选择屏蔽几位(xuan)
     * 
     * @param phone
     * @param hideNum
     * @return
     */
    public static String hideSomeNum(String phone, int hideNum) {
        if (Validators.isEmpty(phone) || phone.length() < 8) {
            return "";
        }

        int start = 3;
        int end = start + hideNum;
        if (phone.length() == 12) {
            start = 4;
            end = start + hideNum;
        }
        char[] ch = phone.toCharArray();
        for (int i = start; i < end; i++) {
            ch[i] = '*';
        }
        return new String(ch);
    }

    /**
     * 获取被隐藏的4位手机号码
     * 
     * @param phone
     * @return
     */
    public static String getHiddenNum(String phone) {
        if (Validators.isEmpty(phone) || phone.length() < 8) {
            return "";
        }
        String result = phone.substring(3, 7);
        if (phone.length() == 12) {
            result = phone.substring(4, 8);
        }
        return result;
    }

    private static String getMobileRegex() {
        return mob.sysOptionService.getPhoneMobileRegex();
    }

    private static String getUnicomRegex() {
        return mob.sysOptionService.getPhoneUnicomRegex();
    }

    private static String getTelecomRegex() {
        return mob.sysOptionService.getPhoneTelecomRegex();
    }

    private MobileUtils() {
    }

    private static <T> T getBean(Class<T> requiredType, ServletContext servletContext) {
        ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
        return context.getBean(requiredType);
    }

    public static void main(String[] args) {
        String m = "(1(3[4-9]|5[01789])\\d{8})|(0001\\d{8})";
        String u = "(1(3[0-3]|5[356])\\d{8})|(0002\\d{8})";
        String t = "(?!00|015|013)(0\\d{9,11})|(0003\\d{8})";

        StopWatch watch = new StopWatch("test");

        String str = "18900000000";
        watch.start("Regex Test");
        for (int i = 0; i < 100000; i++) {
            Pattern.matches(m, str);
            Pattern.matches(u, str);
            Pattern.matches(t, str);
        }
        watch.stop();

        System.out.println(watch.shortSummary());

    }

    /**
     * @param sysOptionService
     *            The sysOptionService to set.
     */
    public void setSysOptionService(SysOptionService sysOptionService) {
        this.sysOptionService = sysOptionService;
    }

}
